package com.qire.manhua.activity.helper;

import android.graphics.Rect;

import com.google.gson.reflect.TypeToken;
import com.qire.common.collect.SafeIterableMap;
import com.qire.common.constant.CacheStorageKey;
import com.qire.common.utils.CacheStorageUtil;
import com.qire.common.utils.EquipmentInfoUtil;
import com.qire.manhua.model.viewModel.impl.ComicReaderViewModel;
import com.qire.manhua.view.comicReader.ComicReaderView.ResourceLocator;
import com.qire.manhua.view.comicReader.LoopComicReaderView;
import com.qire.manhua.view.comicReader.renderer.PictureResource;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map.Entry;

/**
 * 漫画阅读器记录助手
 */
public class ComicReaderRecordHelper implements ResourceLocator {

    private final int ScreenHeight = EquipmentInfoUtil.getScreenHeight();
    private final ComicPopularDataRecorder popularDataRecorder = new ComicPopularDataRecorder();

    private final ComicReaderViewModel viewModel;
    private final LoopComicReaderView loopComicReaderView;

    public ComicReaderRecordHelper(ComicReaderViewModel viewModel, LoopComicReaderView loopComicReaderView) {
        this.viewModel = viewModel;
        this.loopComicReaderView = loopComicReaderView;
    }

    @Override
    public void onLocateResources(PictureResource pictureResource, int comicHeight) {
        // 显示当前阅读位置
        int progress = (pictureResource.calcViewportRect().bottom / ScreenHeight) + 1;
        int totalCount = comicHeight / ScreenHeight;
        viewModel.setReadProgressText(Math.min(progress, totalCount), totalCount);

        // 记录漫画阅读人气记录，以每人每章节阅读屏幕数为人气值
        popularDataRecorder.recordProgress(pictureResource, comicHeight);
    }

    public void onDestroy() {
        popularDataRecorder.recordReportAndReset();
        popularDataRecorder.saveAndExit();
    }

    public void reportComicPopular() {
        popularDataRecorder.recordReportAndReset();
        loopComicReaderView.getReadingComicReaderView().setResourceLocator(this);
    }

    /** 漫画人气数据记录器 */
    private class ComicPopularDataRecorder {
        /** 2次记录超时间隔时间，间隔内不做记录，间隔超时才会重新记录 */
        private final long TIMEOUT_INTERVAL = 60 * 60 * 1000;
        /** 漫画标准基础宽度 */
        private final float COMIC_BASE_WIDTH = 750;
        /** 漫画标准基础高度 */
        private final float COMIC_BASE_HEIGHT = 1334;
        /** 转换成屏幕宽度后，标准一屏漫画高度 */
        private final float COMIC_SCREEN_HEIGHT = EquipmentInfoUtil.getScreenWidth() * (COMIC_BASE_HEIGHT / COMIC_BASE_WIDTH);
        /** 漫画人气记录缓存，用于记录最近阅读的漫画章节中资源的最后阅读时间 */
        private RecordDataMap<String, Long> popularRecordMap = new RecordDataMap<>();

        private int comicHeight;
        private PictureResource startRecordResources;
        private PictureResource lastRecordResources;

        /***********************************************************************
         * <br /> 每次重新进入漫画阅读页，都需要检查是否有记录过人气数据，如果记录过是否超时，超时则需要重新记录
         * <br /> 1.检查是否存在人气记录数据，如果存在判断是否超时
         * <br /> 2.如果超时则清空缓存数据
         * <br /> 3.加载缓存数据，如果超时加载的事清空后的空数据，未超时则加载上次记录的数据。
         ***********************************************************************/
        private ComicPopularDataRecorder() {
            if(!clearPopularDataIfExpired()) {
                Type type = new TypeToken<HashMap<String, Long>>(){}.getType();
                popularRecordMap.putAll(CacheStorageUtil.query(CacheStorageKey.POPULAR_STATISTICAL, type));
            }
        }

        /**
         * 清除人气统计数据如果它过期了的话
         * @return true 有清除 false 没有清除
         */
        private boolean clearPopularDataIfExpired() {
            long lastTime = CacheStorageUtil.queryLong(CacheStorageKey.COMIC_READER_EXIT_TIME);
            if(System.currentTimeMillis() - lastTime > TIMEOUT_INTERVAL) {
                CacheStorageUtil.save(CacheStorageKey.POPULAR_STATISTICAL, popularRecordMap.toMap());
                return true;
            }
            return false;
        }

        public void saveAndExit() {
            CacheStorageUtil.save(CacheStorageKey.POPULAR_STATISTICAL, popularRecordMap.toMap());
            CacheStorageUtil.save(CacheStorageKey.COMIC_READER_EXIT_TIME, System.currentTimeMillis());
        }

        public void reset() {
            comicHeight = 0;
            startRecordResources = null;
            lastRecordResources = null;
        }

        public void recordReportAndReset() {
            if(startRecordResources != null && lastRecordResources != null) {
                Rect startRect = new Rect(startRecordResources.calcViewportRect());
                Rect lastRect = new Rect(lastRecordResources.calcViewportRect());

                startRect.union(lastRect);
                //统计记录以屏幕的左上角作为判定条件，当图片滑过顶部时记录改图片的高度，故多加1屏
                int scrollCount = (int)(startRect.height() / COMIC_SCREEN_HEIGHT) + 1;

                viewModel.reportComicPopular(scrollCount, (int) COMIC_SCREEN_HEIGHT, comicHeight);

                //ToastHelper.showToast("本章阅读了"+statisticalHelper.scrollCount()+"屏" + "总屏:" + comicHeight/screenHeight);
                reset();
            }
        }

        /**
         * 记录阅读人气记录
         * @param pictureResource 当前阅读到的图片资源节点
         * @param comicHeight 漫画的总高度
         */
        private void recordProgress(PictureResource pictureResource, int comicHeight) {

            /***************************************************************************
             * 1.检查资源是否已读过，如果资源本次已读过则不在记录
             * 2.检查资源是否在规定时间内读过，读过则不在记录，超时才记录
             * 3.阅读资源并标记已读，并且在同一次阅读内部在记录（退出阅读页前都算作同一次阅读）
             * 4.记录本次阅读事从该章节的哪一个图片资源节点开始记录的。
             * 5.记录漫画章节总高度
             * 6.记录当前阅读的资源及时间
             ***************************************************************************/

            // 获得当前资源上一次阅读记录时间
            Long resourceLastReadTime = popularRecordMap.getValue(pictureResource.uri);
            Long nowTime = System.currentTimeMillis();

            boolean notAllowedStatistics = (resourceLastReadTime != null) && (nowTime - resourceLastReadTime < TIMEOUT_INTERVAL);

            if(pictureResource.readedState() || notAllowedStatistics)
                return;

            lastRecordResources = pictureResource.reading();

            if(startRecordResources == null) {
                startRecordResources = lastRecordResources;
            }

            this.comicHeight = comicHeight;

            popularRecordMap.putIfAbsent(lastRecordResources.uri, nowTime);

        }

    }

    private class RecordDataMap<K, V> extends SafeIterableMap<K, V> {
        public void putAll(HashMap<K, V> dataMap) {
            if(dataMap != null) {
                for(Entry<K, V> entry : dataMap.entrySet()) {
                    putIfAbsent(entry.getKey(), entry.getValue());
                }
            }
        }

        public HashMap<K, V> toMap() {
            HashMap<K, V> map = new HashMap<>();
            for(Entry<K, V> entry : this) {
                map.put(entry.getKey(), entry.getValue());
            }
            return map;
        }
    }
}
